package cn.bytets.rpc.api.balance;

import cn.bytets.rpc.api.invoke.Invocation;
import cn.bytets.rpc.api.invoke.Invoker;
import cn.bytets.rpc.common.URL;

import java.util.List;

public abstract class AbstractLoadBalance implements LoadBalance{
    /**
     * 根据预热时间的正常运行时间比例计算重量,权重在 1 到 weight(入参)权重之间
     * @param uptime 正常运行时间
     * @param warmup 预热时间
     * @param weight 权重
     * @return
     */
    static int calculateWarmupWeight(int uptime, int warmup, int weight) {
        int ww = (int) ( uptime / ((float) warmup / weight));
        return ww < 1 ? 1 : (Math.min(ww, weight));
    }

    /**
     * 获取调用程序调用的权重，该权重考虑预热时间 如果正常运行时间在预热时间内，权重将按比例减少
     * @param invoker
     * @param invocation
     * @return
     */
    int getWeight(Invoker<?> invoker, Invocation invocation) {
        /**
         * 获取权重,默认为100
         */
        int weight = invoker.getUrl().getMethodParameter(invocation.getMethodName(), "weight", 100);

        if (weight > 0) {
            long timestamp = invoker.getUrl().getParameter("timestamp", 0L);
            if (timestamp > 0L) {
                /**
                 * timestamp 是接口的注册时间
                 * 运行时间
                 */
                long uptime = System.currentTimeMillis() - timestamp;
                if (uptime < 0) {
                    return 1;
                }
                /**
                 * 预热时间,预热越久,则权重越加大,主要作用是让其他消费者经量少调用这个服务,知道预热时间过后恢复正常的权重值
                 */
                int warmup = invoker.getUrl().getParameter("warmup", 10 * 60 * 1000);
                if (uptime > 0 && uptime < warmup) {
                    weight = calculateWarmupWeight((int)uptime, warmup, weight);
                }
            }
        }
        return Math.max(weight, 0);
    }

    @Override
    public  Invoker select(List<Invoker> list, URL url, Invocation invocation) {
        if (list == null || list.isEmpty()) {
            return null;
        }
        if (1==list.size()){
            return list.get(0);
        }
        return doSelect(list,url,invocation);
    }

    protected abstract  Invoker doSelect(List<Invoker> list, URL url, Invocation invocation);
}
